package ua.kpi.ipsa.expert.api.algorithm;

import java.util.*;

import ua.kpi.ipsa.expert.api.algorithm.tokenizer.Tokenizer.Token;

import ua.kpi.ipsa.expert.api.db.*;

/**
 * 
 * @author doctorpro
 * 
 */
public class HashSifting implements Algorithm {

	private static final long PRIMAL = 37;
	private static final int DEFAULT_WINDOW_SIZE = 4;
	private static final int DEFAULT_HASH_STRING_SIZE = 3;
	private static final HashMap<Integer, Token[]> hashes = new HashMap<Integer, Token[]>();

	private DAO dao;

	private long pows[] = new long[1000];

	public HashSifting(DAO dao) {
		this.dao = dao;
	}

	@Override
	public List<PlagiarismHypoTuple> process(int codeToAnalize,
			CodeRanker ranker, ProgressMonitor monitor) {

		try {
			// check all codes

			System.out.println("asdd1");

			// get my guest hash tokens
			Token myHashes[] = null;
			synchronized (hashes) {
				myHashes = hashes.get(codeToAnalize);
				if (myHashes == null) {
					String myText = dao.getCode(codeToAnalize).text;
					// myHashes = hashesize(myText, DEFAULT_HASH_STRING_SIZE,
					// DEFAULT_WINDOW_SIZE);
					hashes.put(codeToAnalize, myHashes);
				}
			}
			System.out.println("asdd2: " + str(myHashes));

			// compare with all the guest codes
			int id = 0;
			int myCodePortionId = dao.getCode(codeToAnalize).codePortionTupleFK;
			while ((id = dao.getNextCodePortionID(id)) < myCodePortionId) {
				List<CodeTuple> cts = dao.getCodeByPortionKey(id);
				for (CodeTuple ct : cts) {
					long[] guestHashes = new long[] { 4, 32, 3, 21, 17, 89, 11,
							31, 31, 2, 3, 31, 31, 31, 4 };
					// hashesize(ct.text,
					// DEFAULT_HASH_STRING_SIZE, DEFAULT_WINDOW_SIZE);

					int coords[] = new int[2];
					// System.out.println("imeem result: " +
					// getSubstring(longToInt(myHashes), longToInt(guestHashes),
					// coords, 3));
				}
			}

			System.out.println("asdd3");
		} catch (Exception ex) {
			ex.printStackTrace();
		}

		return null;
	}

	public int[] getTokens(String s) {

		long myTokens[] = new long[] { 1, 2, 3, 4, 7, 6, 31, 31, 31, 5, 6, 31,
				2, 32, 32, 1, 5 };

		return longToInt(myTokens);
	}

	public int[] longToInt(long[] s) {
		int[] r = new int[s.length];

		for (int i = 0; i < s.length; i++) {
			r[i] = (int) s[i];
		}
		return r;
	}

	public long[] tokenToLong(Token[] s) {
		long[] r = new long[s.length];

		for (int i = 0; i < s.length; i++) {
			r[i] = s[i].getID();
		}
		return r;
	}

	public long[] hashesize(String text, int hashedStringSize, int windowSize) {

		// get the tokenz
		int[] tokens = getTokens(text);

		// get the raw hashez
		long[] rawHashes = new long[tokens.length - hashedStringSize + 1];
		long[] result = new long[(int) Math.ceil(((double) rawHashes.length)
				/ windowSize)];
		for (int i = 0; i < rawHashes.length; i++) {
			rawHashes[i] = hash(tokens, i, i + hashedStringSize - 1);
		}

		int i = 0;
		while (i * windowSize < rawHashes.length) {
			long minValue = rawHashes[i * windowSize];
			for (int j = i * windowSize; j < min((i + 1) * windowSize,
					rawHashes.length); j++) {
				if (rawHashes[j] < minValue) {
					minValue = rawHashes[j];
				}
				result[i] = minValue;
			}
			i++;
		}

		return result;
	}

	public int min(int a, int b) {
		return a <= b ? a : b;
	}

	@Override
	public String getName() {
		return "HashSifting";
	}

	@Override
	public String[] getCodePresentationClasses() {
		return new String[] {};
	}

	public boolean getSubstring(int s1[], int s2[], int coords[],
			int substringLength) {

		boolean found = false;
		int foundHashValue;

		// create set
		long[] set = new long[s1.length - substringLength + 1];
		for (int i = 0; i + substringLength - 1 < s1.length; i++) {
			set[i] = hash(s1, i, i + substringLength - 1);
		}

		// check hash in set
		for (int i = 0; i + substringLength - 1 < s2.length; i++) {

			int j = contains(set, hash(s2, i, i + substringLength - 1));

			if (j != -1) {
				if (equals(s1, s2, j, i, substringLength)) {
					coords[0] = j;
					coords[1] = i;
					return true;
				}
			}
		}

		return false;
	}

	public int contains(long[] set, long ex) {
		for (int i = 0; i < set.length; i++) {
			if (set[i] == ex) {
				return i;
			}
		}

		return -1;
	}

	public boolean equals(int s1[], int s2[], int begin1, int begin2, int length) {

		for (int i = 0; i < length; i++) {
			if (s1[begin1 + i] != s2[begin2 + i]) {
				return false;
			}
		}

		return true;
	}

	/**
	 * 
	 * @param s
	 * @param begin
	 * @param end
	 * @return
	 */
	public long hash(int s[], int begin, int end) {

		if (begin > end) {
			int t = end;
			end = begin;
			begin = t;
		}

		long result = 0;

		for (int i = begin, c = end - begin; i <= end; i++, c--) {
			result += s[i] * pow(c);
		}

		return result;
	}

	/**
	 * 
	 * @param pow
	 * @return
	 */
	public long pow(int pow) {

		if (pow > pows.length) {
			pows = new long[2 * pow];
		}

		if (pows[pow] == 0) {
			pows[pow] = (long) Math.pow(PRIMAL, pow);
		}

		return pows[pow];
	}

	public String str(Token[] a) {
		String res = "";
		for (int i = 0; i < a.length; i++) {
			res += a[i] + "; ";
		}
		return res;
	}

	public String str(int[] a) {
		String res = "";
		for (int i = 0; i < a.length; i++) {
			res += a[i] + "; ";
		}
		return res;
	}
}
